package cn.yx.common.core.util.reflect;

import cn.yx.common.core.constant.message.reflect.ConvertUtilMessageKey;
import cn.yx.common.core.exception.CommonException;
import cn.yx.common.core.util.json.jackson.JsonUtil;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * <p>借助Java反射完成对象转Map的功能</p>
 *
 * @author Wgssmart
 */
@Slf4j
public final class ConvertUtil {

    /**
     * Map初始化大小
     */
    private static final int MAP_INIT_SIZE = 1;

    private ConvertUtil() {
    }

    /**
     * 把Object转化成Map<String, String>对象，key为属性名，value为值，如果值为非基础类型（包括基础类型的包装类），
     * 则value为值对象的JSON字符串
     *
     * @param obj
     * @return
     */
    public static Map<String, String> toStringMap(Object obj) {
        if (Objects.isNull(obj)) {
            return null;
        }
        Map<String, String> map = new HashMap<>(MAP_INIT_SIZE);
        Class<?> clazz = obj.getClass();
        for (Field field : clazz.getDeclaredFields()) {
            field.setAccessible(true);
            String fieldName = field.getName();
            String fieldValue = "";
            try {
                if (cn.hutool.core.util.ClassUtil.isBasicType(field.getType())
                        || ClassUtil.isNumberType(field.getType())) {
                    // 基础数据类型或数字类型直接转换成字符串
                    fieldValue = Objects.isNull(field.get(obj)) ? "" : field.get(obj).toString();
                } else {
                    // 字符串或其他自定义对象类型，转成JSON字符串
                    fieldValue = JsonUtil.toJsonStr(field.get(obj));
                }
            } catch (IllegalAccessException e) {
                log.error("object to string map error: {}, object class: {}", e.getMessage(), obj.getClass().getName());
                throw new CommonException(ConvertUtilMessageKey.TO_STRING_MAP_ERROR, e);
            }
            map.put(fieldName, fieldValue);
        }
        return map;
    }

    /**
     * 把Object转化成Map<String, Object>对象，key为属性名，value为值对象
     *
     * @param obj
     * @return
     */
    public static Map<String, Object> toObjectMap(Object obj) {
        if (Objects.isNull(obj)) {
            return null;
        }
        Map<String, Object> map = new HashMap<>(MAP_INIT_SIZE);
        Class<?> clazz = obj.getClass();
        for (Field field : clazz.getDeclaredFields()) {
            field.setAccessible(true);
            String fieldName = field.getName();
            try {
                map.put(fieldName, field.get(obj));
            } catch (IllegalAccessException e) {
                log.error("object to object map error: {}, object class: {}", e.getMessage(), obj.getClass().getName());
                throw new CommonException(ConvertUtilMessageKey.TO_OBJECT_MAP_ERROR, e);
            }
        }
        return map;
    }

}
